package slider_verify

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"gitee.com/binny_w/go-util"
	"image"
	"image/color"
	"image/png"
)

type point struct {
	X int
	Y int
}

type cutoutRet struct {
	Point         *point
	BackgroundImg string
	BlockImg      string
}

var i = 0

func generate() (*cutoutRet, error) {
	var bgImage, bkImage *imageBuf
	var err error
	bgImgBs := bgBytes[i]
	if i++; i >= len(bgBytes) {
		i = 0
	}
	if bgImage, err = newImageBuf(bgImgBs); err != nil {
		return nil, err
	}
	if bkImage, err = newImageBuf(blk); err != nil {
		return nil, err
	}
	ret := new(cutoutRet)
	bgWidth := bgImage.getWidth()
	bgHeight := bgImage.getHeight()
	bkWidth := bkImage.getWidth()
	bkHeight := bkImage.getHeight()
	ret.Point = randPoint(bgWidth, bgHeight, bkWidth, bkHeight)
	newBkImage := &imageBuf{
		w: bkWidth,
		h: bkHeight,
		i: image.NewNRGBA(image.Rect(0, 0, bkWidth, bkHeight)),
	}
	cutOut(bgImage, bkImage, newBkImage, ret.Point)
	ret.BackgroundImg, err = img2Base64(bgImage)
	if err != nil {
		return nil, err
	}
	ret.BlockImg, err = img2Base64(newBkImage)
	if err != nil {
		return nil, err
	}
	return ret, nil
}

func randPoint(bgWidth, bgHeight, bkWidth, bkHeight int) *point {
	wDiff := bgWidth - bkWidth
	hDiff := bgHeight - bkHeight
	var x, y int
	if wDiff <= 0 {
		x = 5
	} else {
		x = util.RandInt(wDiff-100) + 100
	}
	if hDiff <= 0 {
		y = 5
	} else {
		y = util.RandInt(hDiff) + 5
	}
	return &point{x, y}
}

func cutOut(bgImage, bkImage, newBkImage *imageBuf, point *point) {
	var values [9]color.RGBA64
	bkWidth := bkImage.getWidth()
	bkHeight := bkImage.getHeight()
	white := color.White
	for i := 0; i < bkWidth; i++ {
		for j := 0; j < bkHeight; j++ {
			pixel := bkImage.getRGBA(i, j)
			if pixel.A > 0 {
				newBkImage.setRGBA(i, j, bgImage.getRGBA(point.X+i, point.Y+j))
				readNeighborPixel(bgImage, point.X+i, point.Y+j, &values)
				bgImage.setRGBA(point.X+i, point.Y+j, white)
			}
			if i == (bkWidth-1) || j == (bkHeight-1) {
				continue
			}
			rightPixel := bkImage.getRGBA(i+1, j)
			bottomPixel := bkImage.getRGBA(i, j+1)
			if (pixel.A > 0 && rightPixel.A == 0) ||
				(pixel.A == 0 && rightPixel.A > 0) ||
				(pixel.A > 0 && bottomPixel.A == 0) ||
				(pixel.A == 0 && bottomPixel.A > 0) {
				newBkImage.setRGBA(i, j, white)
				bgImage.setRGBA(point.X+i, point.Y+j, white)
			}
		}
	}
}

func readNeighborPixel(img *imageBuf, x, y int, pixels *[9]color.RGBA64) {
	xStart := x - 1
	yStart := y - 1
	current := 0
	for i := xStart; i < 3+xStart; i++ {
		for j := yStart; j < 3+yStart; j++ {
			tx := i
			if tx < 0 {
				tx = -tx
			} else if tx >= img.getWidth() {
				tx = x
			}
			ty := j
			if ty < 0 {
				ty = -ty
			} else if ty >= img.getHeight() {
				ty = y
			}
			pixels[current] = img.getRGBA(tx, ty)
			current++
		}
	}
}

func img2Base64(image *imageBuf) (string, error) {
	var buf bytes.Buffer
	if err := png.Encode(&buf, image.i); err != nil {
		return "", fmt.Errorf("unable to encode png: %w", err)
	}
	data := buf.Bytes()
	return base64.StdEncoding.EncodeToString(data), nil
}
